from fastapi import APIRouter, Depends, Query, HTTPException, Path, Body
from app.database.database import get_db
from app.services.user_service import get_user_by_id
from app.services.directory_service import (
    create_directory, get_directories, get_directory_by_id, update_directory,
    delete_directory, get_directory_tree, move_files_to_directory,
    get_root_files, get_files_in_directory, move_items_to_directory,
    batch_delete_items
)
from sqlalchemy.orm import Session
from typing import Optional, List, Dict, Any
import logging
from pydantic import BaseModel, Field
from app.services.auth_service import get_current_user
from fastapi.security import OAuth2PasswordBearer
from app.database.models import User
from app.utils.response_utils import ResponseResult
from app.schemas.directory_schema import (
    DirectoryCreate, DirectoryUpdate, DirectoryResponse, DirectoryTreeNode,
    DirectoryMoveRequest, BatchDeleteRequest
)
from app.schemas.file_schema import FileResponse
from datetime import datetime

# 配置日志记录器
logger = logging.getLogger(__name__)

oauth2_scheme = OAuth2PasswordBearer(
    tokenUrl="/auth/oauth/token",
    scheme_name="OAuth2PasswordBearer",
    auto_error=True
)

router = APIRouter(
    prefix="/api",
    tags=["目录管理"],
    responses={
        401: {"description": "未认证"},
        403: {"description": "无权限访问"},
        404: {"description": "资源不存在"},
        500: {"description": "服务器内部错误"}
    }
)

async def get_current_user_from_token(
    token: str = Depends(oauth2_scheme),
    db: Session = Depends(get_db)
) -> User:
    """从token中获取当前用户"""
    return get_current_user(db, token)

@router.post("/directories",
    summary="创建目录",
    description="创建一个新的目录，可以创建在根目录或指定的父目录下。",
    tags=["目录管理"],
    response_model=ResponseResult
)
async def create_directory_endpoint(
    directory: DirectoryCreate,
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """创建目录
    
    - **name**: 目录名称
    - **parent_id**: 父目录ID，0表示根目录
    
    返回:
        - **id**: 目录ID
        - **name**: 目录名称
        - **path**: 目录完整路径
        - **parent_id**: 父目录ID
    """
    try:
        directory = create_directory(
            db=db,
            user_id=current_user.id,
            name=directory.name,
            parent_id=directory.parent_id
        )
        
        return ResponseResult(
            code=200,
            message="目录创建成功",
            data=DirectoryResponse.from_orm(directory)
        )
    except HTTPException as e:
        raise e
    except Exception as e:
        logger.error(f"创建目录失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"创建目录失败: {str(e)}")

@router.get("/directories",
    summary="获取目录列表",
    description="获取指定父目录下的所有子目录。如果不指定父目录ID，则获取根目录下的所有目录。",
    tags=["目录管理"],
    response_model=ResponseResult
)
async def get_directories_endpoint(
    parent_id: Optional[int] = Query(0, description="父目录ID，0表示获取根目录下的目录"),
    include_deleted: bool = Query(False, description="是否包含已删除目录"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """获取目录列表
    
    - **parent_id**: 父目录ID，0表示获取根目录下的目录
    - **include_deleted**: 是否包含已删除目录
    """
    try:
        directories = get_directories(
            db=db,
            user_id=current_user.id,
            parent_id=parent_id,
            include_deleted=include_deleted
        )
        
        return ResponseResult(
            code=200,
            message="获取目录列表成功",
            data={"items": [DirectoryResponse.from_orm(dir) for dir in directories]}
        )
    except HTTPException as e:
        raise e
    except Exception as e:
        logger.error(f"获取目录列表失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"获取目录列表失败: {str(e)}")

@router.get("/directories/tree",
    summary="获取目录树",
    description="获取用户的完整目录树结构，包括每个目录下的文件数量。适合前端构建树形目录导航。",
    tags=["目录管理"],
    response_model=Dict[str, Any]
)
async def get_directory_tree_endpoint(
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """获取目录树结构
    
    返回:
        - **tree**: 目录树结构，每个节点包含id、name、path、children等信息
    """
    logger.debug(f"接收到获取目录树请求: user_id={current_user.id}")
    
    tree = get_directory_tree(
        db=db,
        user_id=current_user.id
    )
    
    return ResponseResult.success(
        data={"tree": tree},
        message="获取目录树成功"
    )

@router.get("/directories/{directory_id}",
    summary="获取目录详情",
    description="获取指定ID的目录详细信息。如果ID为0，则返回根目录的虚拟详情。",
    tags=["目录管理"],
    response_model=Dict[str, Any]
)
async def get_directory_endpoint(
    directory_id: int = Path(..., description="目录ID，0表示根目录"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """获取目录详情
    
    返回:
        - **id**: 目录ID
        - **name**: 目录名称
        - **path**: 目录完整路径
        - **parent_id**: 父目录ID
        - **create_time**: 创建时间
        - **update_time**: 更新时间
    """
    logger.debug(f"接收到获取目录详情请求: user_id={current_user.id}, directory_id={directory_id}")
    
    # 特殊处理根目录
    if directory_id == 0:
        # 创建一个虚拟的根目录详情
        root_directory = {
            "id": 0,
            "name": "根目录",
            "parent_id": None,
            "user_id": current_user.id,
            "path": "/",
            "create_time": datetime.utcnow(),
            "update_time": datetime.utcnow(),
            "is_deleted": False
        }
        
        return ResponseResult.success(
            data=root_directory,
            message="获取根目录详情成功"
        )
    
    # 正常获取目录
    directory = get_directory_by_id(
        db=db,
        directory_id=directory_id,
        user_id=current_user.id
    )
    
    if not directory:
        raise HTTPException(status_code=404, detail="目录不存在")
    
    return ResponseResult.success(
        data=DirectoryResponse.from_orm(directory),
        message="获取目录详情成功"
    )

@router.put("/directories/{directory_id}",
    summary="更新目录",
    description="修改指定ID的目录信息，可以更新目录名称或移动目录位置。",
    tags=["目录管理"],
    response_model=Dict[str, Any]
)
async def update_directory_endpoint(
    directory_id: int = Path(..., description="目录ID"),
    directory_update: DirectoryUpdate = Body(..., description="更新的目录信息"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """更新目录信息
    
    - **name**: 更新的目录名称(可选)
    - **parent_id**: 更新的父目录ID(可选)，设为null表示移动到根目录
    
    返回:
        - **id**: 目录ID
        - **name**: 更新后的目录名称
        - **path**: 更新后的目录完整路径
        - **parent_id**: 更新后的父目录ID
    """
    logger.debug(f"接收到更新目录请求: user_id={current_user.id}, directory_id={directory_id}")
    
    result = update_directory(
        db=db,
        directory_id=directory_id,
        user_id=current_user.id,
        name=directory_update.name,
        parent_id=directory_update.parent_id
    )
    
    return ResponseResult.success(
        data=DirectoryResponse.from_orm(result),
        message="目录更新成功"
    )

@router.delete("/directories/{directory_id}",
    summary="删除目录",
    description="删除指定ID的目录，可选择软删除(移至回收站)或永久删除。永久删除将同时删除目录下的所有文件和子目录。",
    tags=["目录管理"],
    response_model=Dict[str, Any]
)
async def delete_directory_endpoint(
    directory_id: int = Path(..., description="目录ID"),
    permanent: bool = Query(False, description="是否永久删除，默认为软删除"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """删除目录
    
    默认进行软删除（移至回收站），如果指定permanent=true则永久删除
    
    返回:
        - **is_permanent**: 是否执行了永久删除
    """
    logger.debug(f"接收到删除目录请求: user_id={current_user.id}, directory_id={directory_id}, permanent={permanent}")
    
    delete_directory(
        db=db,
        directory_id=directory_id,
        user_id=current_user.id,
        permanent=permanent
    )
    
    message = "目录永久删除成功" if permanent else "目录已移至回收站"
    return ResponseResult.success(
        data={"is_permanent": permanent},
        message=message
    )

class MoveItemsRequest(BaseModel):
    """移动文件和目录请求模型"""
    file_ids: Optional[List[int]] = Field([], description="要移动的文件ID列表", example=[1, 2, 3])
    directory_ids: Optional[List[int]] = Field([], description="要移动的目录ID列表", example=[1, 2, 3])
    target_directory_id: Optional[int] = Field(None, description="目标目录ID，为null表示移动到根目录")

@router.post("/directories/move-items",
    summary="将文件和目录移动到指定目录",
    description="将一个或多个文件和目录移动到指定目录。如果目标目录ID为null，表示将文件和目录移出目录（放置在根目录下）。",
    tags=["目录管理"],
    response_model=ResponseResult
)
async def move_items_endpoint(
    request: MoveItemsRequest,
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """将文件和目录移动到指定目录
    
    - **request**: 包含文件ID列表、目录ID列表和目标目录ID的请求体
    
    返回:
        - **files**: 文件移动结果，包含成功数量、失败数量和失败列表
        - **directories**: 目录移动结果，包含成功数量、失败数量和失败列表
        - **total_success_count**: 总成功数量
        - **total_failed_count**: 总失败数量
    """
    try:
        result = move_items_to_directory(
            db=db,
            user_id=current_user.id,
            file_ids=request.file_ids,
            directory_ids=request.directory_ids,
            target_directory_id=request.target_directory_id
        )
        
        total_success = result["total_success_count"]
        return ResponseResult(
            code=200,
            message=f"成功移动 {total_success} 个项目（{result['files']['success_count']} 个文件，{result['directories']['success_count']} 个目录）",
            data=result
        )
    except HTTPException as e:
        raise e
    except Exception as e:
        logger.error(f"移动项目失败: {str(e)}")
        raise HTTPException(status_code=500, detail=f"移动项目失败: {str(e)}")

@router.post("/directories/batch-delete",
    summary="批量删除目录和文件",
    description="批量删除多个目录和文件。支持递归删除目录内容，可选择软删除或永久删除。提供详细的操作结果统计。",
    tags=["目录管理"],
    response_model=ResponseResult
)
async def batch_delete_items_endpoint(
    request: BatchDeleteRequest,
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """批量删除目录和文件
    
    - **request**: 包含目录ID列表、文件ID列表、是否永久删除和是否递归删除的请求体
    
    返回:
        - **directories**: 目录删除结果，包含成功数量、失败数量、失败列表和受影响的文件数量
        - **files**: 文件删除结果，包含成功数量、失败数量和失败列表
        - **total_success_count**: 总成功数量
        - **total_failed_count**: 总失败数量
        - **is_permanent**: 是否执行了永久删除
    """
    logger.info(f"接收到批量删除请求: user_id={current_user.id}, directory_ids={request.directory_ids}, file_ids={request.file_ids}, permanent={request.permanent}, recursive={request.recursive}")
    
    if not request.directory_ids and not request.file_ids:
        return ResponseResult.error(
            code=400,
            message="至少需要提供一个目录ID或文件ID"
        )
    
    result = batch_delete_items(
        db=db,
        user_id=current_user.id,
        directory_ids=request.directory_ids,
        file_ids=request.file_ids,
        permanent=request.permanent,
        recursive=request.recursive
    )
    
    dir_success = result["directories"]["success_count"]
    file_success = result["files"]["success_count"]
    total_success = result["total_success_count"]
    
    message = f"成功删除 {total_success} 个项目"
    if dir_success > 0 and file_success > 0:
        message = f"成功删除 {total_success} 个项目（{dir_success} 个目录，{file_success} 个文件）"
    elif dir_success > 0:
        message = f"成功删除 {dir_success} 个目录"
    elif file_success > 0:
        message = f"成功删除 {file_success} 个文件"
    
    return ResponseResult.success(
        data=result,
        message=message
    )

@router.get("/directories/{directory_id}/files",
    summary="获取目录下的文件",
    description="获取指定目录下的所有文件列表。如果目录ID为0，则获取根目录下的文件。",
    tags=["目录管理"],
    response_model=Dict[str, Any]
)
async def get_directory_files_endpoint(
    directory_id: int = Path(..., description="目录ID, 0表示根目录"),
    current_user: User = Depends(get_current_user_from_token),
    db: Session = Depends(get_db)
):
    """获取目录下的文件
    
    返回:
        - **items**: 文件列表
    """
    logger.debug(f"接收到获取目录文件请求: user_id={current_user.id}, directory_id={directory_id}")
    
    # 特殊处理根目录情况
    if directory_id == 0:
        files = get_root_files(db=db, user_id=current_user.id)
        return ResponseResult.success(
            data={"items": [FileResponse.from_orm(file) for file in files]},
            message="获取根目录文件成功"
        )
    
    # 对于非根目录，验证目录是否存在
    directory = get_directory_by_id(db, directory_id, current_user.id)
    if not directory:
        raise HTTPException(status_code=404, detail="目录不存在")
    
    files = get_files_in_directory(
        db=db,
        user_id=current_user.id,
        directory_id=directory_id
    )
    
    return ResponseResult.success(
        data={"items": [FileResponse.from_orm(file) for file in files]},
        message="获取目录文件成功"
    ) 